package cn.maihe.elg.operation.centers.follow.handler;

import cn.maihe.elg.operation.centers.follow.auth.AuthHelper;
import cn.maihe.elg.operation.centers.follow.config.FollowConfig;
import cn.maihe.elg.operation.centers.follow.enums.FollowRespCode;
import cn.maihe.elg.operation.centers.follow.exception.FollowException;
import cn.maihe.elg.operation.centers.supports.BaseCenterService;
import cn.maihe.elg.operation.centers.supports.CenterTradeContext;
import cn.maihe.elg.operation.exception.CenterException;
import cn.maihe.elg.operation.model.dto.BaseResp;
import cn.maihe.elg.operation.model.enums.CenterNoEnum;
import cn.maihe.elg.operation.utils.ElgLogger;
import cn.maihe.elg.operation.utils.MD5FileUtil;
import cn.maihe.elg.operation.utils.ValidateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description
 * @Author WJH
 * @Date 2021/04/22
 */
@Slf4j
@Service
public abstract class FollowCenterTradeService<REQ extends FollowBaseReq, RESP extends BaseResp> extends BaseCenterService<REQ, RESP> {

    @Resource
    private FollowConfig followConfig;

    @Value("${spring.profiles.active}")
    private String activeProfile;

    /**
     * @param orgCode
     * @param reqParams
     * @param attrMap   附加属性值
     * @return
     */
    @Override
    public RESP doService(String orgCode, SignReqDTO reqParams, String params, Map<String, Object> attrMap) {
        ElgLogger.info(log, log -> log.info("[{}:{}][{}] => 原始请求参数:{} 附属属性:{}", centerNoEnum.getCenterNo(), orgCode, tradeService.tradeType(), toJsonString(reqParams), toJsonString(attrMap)));
        CenterNoEnum centerNoEnum = getCenterNoEnum();

        ElgLogger.info(log, log -> log.info("请求报文:{}", toJsonString(reqParams)));
        if (!reqParams.getAppid().equals(followConfig.getAppId())) {
            throw FollowException.of(FollowRespCode.FAILURE, "appId错误", null);
        }
        if (!reqParams.getVersion().equals(followConfig.getVersion())) {
            throw FollowException.of(FollowRespCode.FAILURE, "version错误", null);
        }
        //todo  验签
        Map<String, String> map = new HashMap();
        map.put("appid", reqParams.getAppid());
        map.put("requestid", reqParams.getRequestid());
        map.put("timestamp", reqParams.getTimestamp());
        map.put("version", reqParams.getVersion());
        map.put("data", MD5FileUtil.getMD5String(reqParams.getData()));
        map.put("appsecret", followConfig.getAppSecret());
        String sortString = AuthHelper.getSortString(map);
        String sign = AuthHelper.SHA1(sortString);
        if (!sign.equals(reqParams.getSign())) {
            if ("prod".equals(activeProfile)) {
                throw FollowException.of(FollowRespCode.FAILURE, "验签错误", null);
            } else {
                log.warn("{}环境验签失败,本地签名结果{}", activeProfile, sign);
            }
        }
        //反序列化
        REQ req = this.buildReq(params);
        //通过比较 反序列化不同
//        String data = toJsonString(req.getData());
//        if(data.equals(reqParams.getData())){
//            ElgLogger.info(log, log -> log.info("[相同{} :{}", data));
//        }else{
//            ElgLogger.info(log, log -> log.info("[不同{} :{}", data,reqParams.getData()));
//        }


        //上下文
        CenterTradeContext context = buildCenterTradeContext(req, centerNoEnum, orgCode, attrMap);

        //参数格式规范校验
        verifyParam(context);

        RESP resp = null;
        try {
            resp = (RESP) processService(context);
            context.setResp(resp);
        } catch (Exception e) {
            if (e instanceof CenterException) {
                throw e;
            }
            throw CenterException.exception("处理异常:" + e.getMessage(), e);
        }
        // 响应报文无需签名&加密
        return resp;
    }

    private CenterTradeContext buildCenterTradeContext(REQ req, CenterNoEnum centerNoEnum, String orgCode, Map<String, Object> attrMap) {
        CenterTradeContext context = new CenterTradeContext(req, centerNoEnum.getCenterNo(), orgCode, getCurCenterId(centerNoEnum), getOrgId(orgCode));
        context.putAll(attrMap);
        return context;
    }


    /**
     * 具体业务处理
     *
     * @param context
     */
    public abstract RESP processService(CenterTradeContext<REQ, RESP> context);

    /**
     * 参数校验：参数规范校验，涉及业务需落库的后置processService处理
     *
     * @param context
     */
    protected void verifyParam(CenterTradeContext<REQ, RESP> context) {
        try {
            ValidateUtil.validate(context.getReq());
        } catch (Exception e) {
            throw CenterException.exception("参数校验失败:" + e.getMessage(), e);
        }
    }

    protected REQ buildReq(String params) {
        try {
            return objectMapper.readValue(params, this.reqClass);
        } catch (IOException e) {
            throw CenterException.exception("反序列化异常", e);
        }
    }


}
